import * as THREE from "../../../modules/three/three.module.js";
import {toFixedVector} from "../lib/util/StaticMethods.js";

const origin = new THREE.Vector3(0,0,0);
const cameraUp = new THREE.Vector3(0,0,1);
const quat = new THREE.Quaternion()
const _euler = new THREE.Euler()

export function computeSizeInPlane(worldPoints, plane) {
  let rotateMat = new THREE.Matrix4().lookAt(origin, plane.normal, cameraUp);
  const planeMatInv = new THREE.Matrix4().copy(rotateMat).invert();
  return computeSizeInFrame(worldPoints, planeMatInv)
}

export function computeSizeInFrame(worldPoints, planeMatInv) {
  const planePoints = worldPoints.map(it => it.clone().applyMatrix4(planeMatInv));
  const box3 = new THREE.Box3().setFromPoints(planePoints);
  const size = box3.getSize(new THREE.Vector3());

  return size;
}

// 工作区辅助平面
export default class PlaneRefVO {
  // 旋转时只允许绕Z轴旋转, 保证平面是铅锤的
  static rotateOnlyZ = true;

  plane = new THREE.Plane();
  width = 1;
  height = 1;
  // 世界坐标
  pos = new THREE.Vector3();
  rot = []

  initSize(w, h) {
    this.width = w;
    this.height = h;
    return this;
  }
  // 返回 true 表示 该辅助平面不是墙面（立面）
  notWall() {
    return Math.abs(this.plane.normal.z) > 0.1
  }

  grounding() {
    return Math.abs(this.plane.normal.z) >= 0.98
  }

  createPlaneAndMat() {
    if (!this.rot.length) {
      quat.setFromUnitVectors(new THREE.Vector3(0, 0, 1), this.plane.normal)
      _euler.setFromQuaternion(quat)
      this.rot = [_euler.x, _euler.y, _euler.z]
    }
    const [x, y, z] = this.rot
    const euler = new THREE.Euler(x, y, z)
    const normal = new THREE.Vector3().set(0,0,-1).applyEuler(euler)
    const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(normal, this.pos)
    // planeMat 是和几何平面一一对应的
    const planeMat = new THREE.Matrix4()
    const uz = normal
    const uy = new THREE.Vector3(0, 0, 1)
    if (this.grounding()) {
      uy.set(0, 1, 0)
    }
    const ux = uy.clone().cross(uz).normalize()
    uy.copy(uz).cross(ux).normalize()
    planeMat.makeBasis(ux, uy, uz)
    const planeCenter = plane.projectPoint(new THREE.Vector3(0,0,0), new THREE.Vector3())
    planeMat.setPosition(planeCenter.x, planeCenter.y, planeCenter.z)
    return [plane, planeMat]
  }

  toJsonObj() {
    const obj = {width: this.width, height: this.height, rot: this.rot};
    obj.plane = this.plane.normal.toArray().concat(this.plane.constant);
    obj.pos = toFixedVector(this.pos, 3).toArray();
    return obj;
  }

  fromJsonObj(jsonObj) {
    this.plane.setComponents(...jsonObj.plane);
    this.pos.fromArray(jsonObj.pos);
    this.width = jsonObj.width;
    this.height = jsonObj.height;
    if (jsonObj.rot) {
      this.rot = jsonObj.rot
    }
    return this;
  }
}
